package llmserviceopenai.service

import llmserviceopenai.model.ChatCompletionRequest
import llmserviceopenai.model.ChatCompletionResponse
import llmserviceopenai.tools.toPayloadJson
import io.ktor.client.*                          // HttpClient
import io.ktor.client.engine.cio.*              // CIO
import io.ktor.client.plugins.contentnegotiation.* // ContentNegotiation
import io.ktor.client.request.*                 // post, setBody, header
import io.ktor.client.statement.*               // HttpResponse
import io.ktor.http.*                           // ContentType, HttpHeaders
import io.ktor.serialization.kotlinx.json.*     // json()
import io.ktor.client.call.*                    // 新增：ClientRequestException, ServerResponseException
import io.ktor.client.plugins.*                 // 可选：用于调试或超时插件
import kotlinx.serialization.json.Json
import org.slf4j.LoggerFactory
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import java.util.concurrent.TimeUnit

import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.MediaType.Companion.toMediaType

class ChatService {
    private val logger = LoggerFactory.getLogger(ChatService::class.java)

    // 使用统一的 JSON 配置（确保兼容性）
    private val json = Json {
        ignoreUnknownKeys = true  // 忽略未知字段（防止后端新增字段导致崩溃）
        explicitNulls = false     // null 字段可省略
    }

    private val client = HttpClient(CIO) {
        install(ContentNegotiation) {
            json(json)
        }

        // 链接超时配置
        install(HttpTimeout) {
            requestTimeoutMillis = 600_00
            connectTimeoutMillis = 30_000
            socketTimeoutMillis = 600_00
        }
    }

    // sxf
//    private val backendUrl = "http://10.10.1.182:8001/v1/chat/completions"
//    private val apiKey =
//        "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2MTk1MGFjYmYyMDM0NjZhODU5YmM4NWYxYTIyYzQzZSIsIm1ldGhvZHMiOiJQT1NUIiwiaWF0IjoiMTc1MTAxNzg1MSIsImV4cCI6IjE3NTEwMjE0NTEifQ.mcma-ZRDclpgKJCa8F0noPJStRKF7K40erbow3RctcrfVeYQHQQoGZvhng4MLa9EbBidAdK6gKEUOdD2fBMKBLWdwhWRmHkwdSrPJa34wqa0htT8BzcyNAyLED0FCa4ZDKnkqP--2OmvQTNQMlx2JNTDGU8oq-Dh-maU-dInyK-Szx-2W6fDdW-fyHclW3T5ChdTOJ5n8XCkDrpjE49CG1hTrbPwbv2IEsf_B7Ox-Jdn7PWAkhvtOCqAOI2qXGdti-zw-VUitwTZ62FJixvoyGREc98p_tCwFBM37IaJqKt08dpAqCu-yXD1ijvBwphrDI_TMa-Yd-SgYpZgS4ddhA"

    // vllm
    private val backendUrl = "http://10.10.1.166:10010/v1/chat/completions"
    private val apiKey = "EMPTY"

    // ollama
//    private val backendUrl = "http://10.10.1.128:11434/v1/chat/completions"
//    private val apiKey = "EMPTY"


    // 拿milvus类
//    private val application = call.application

    suspend fun handleChatCompletion(request: ChatCompletionRequest): ChatCompletionResponse {
        logger.info("Forwarding request to backend: $request")

        // 重新构建请求参数
        println(request.toPayloadJson())

        try {
            // 向真实后端发起请求
            val response: HttpResponse = client.post(backendUrl) {
                contentType(ContentType.Application.Json)
                setBody(request.toPayloadJson())
                header(HttpHeaders.Authorization, "Bearer $apiKey")
            }

            // 直接将后端的完整响应反序列化为 ChatCompletionResponse
            val openAIResponse = response.body<ChatCompletionResponse>()
            logger.info("Received valid OpenAI-style response id is : ${openAIResponse.id}")
            logger.info("Received valid OpenAI-style response: ${openAIResponse}")

            return openAIResponse

        } catch (e: ClientRequestException) {
            val status = e.response.status
            val errorBody = e.response.bodyAsText()
            logger.error("Client error ($status): $errorBody")
            throw e
        } catch (e: ServerResponseException) {
            val status = e.response.status
            val errorBody = e.response.bodyAsText()
            logger.error("Server error ($status): $errorBody")
            throw e
        } catch (e: Exception) {
            logger.error("Unexpected error while calling backend", e)
            throw e
        }
    }

    fun streamChatCompletion(request: ChatCompletionRequest): Flow<String> = flow {
        val payload = request.toPayloadJson()
        logger.info("streamChatCompletion payload is $payload")

        val client = OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(0, TimeUnit.SECONDS) // 重要：禁用读取超时，允许长连接流式
            .build()

        val body = payload.toString().toRequestBody("application/json".toMediaType())

        val httpRequest = Request.Builder()
            .url(backendUrl)
            .post(body)
            .addHeader("Authorization", "Bearer $apiKey")
            .addHeader("Content-Type", "application/json")
            .build()

        val startTime = System.nanoTime()
        var ttft: Long? = null
        var firstTokenReceived = true

        try {
            client.newCall(httpRequest).execute().use { response ->
                if (!response.isSuccessful) {
                    throw Exception("HTTP error: ${response.code} - ${response.message}")
                }

                // OkHttp 提供了流式响应体 InputStream
                val reader = response.body?.charStream()
                    ?: throw Exception("Response body is null")

                val bufferedReader = reader.buffered()

                var line: String?
                while (bufferedReader.readLine().also { line = it } != null) {
                    val event = line!!.trim()
                    if (event.startsWith("data:")) {
                        val part = event.removePrefix("data:").trim()
                        val currentTime = System.nanoTime()
                        if (firstTokenReceived && part.isNotEmpty() && part != "[DONE]") {
                            ttft = currentTime - startTime
                            logger.info("首token 耗时为 ${TimeUnit.NANOSECONDS.toMillis(ttft!!)} ms")
                            firstTokenReceived = false
                        }
                        logger.info("ChatService part is $part")

                        if (part == "[DONE]") {
                            emit("[DONE]")
                            return@flow
                        } else if (part.isNotEmpty()) {
                            emit(part)
                        }
                    }
                }
            }
        } catch (e: Exception) {
            logger.error("streamChatCompletion failed: ${e.message}", e)
            throw e
        }
    }
}
